package frame.core;

import frame.pojo.Configuration;
import frame.pojo.MapperStatement;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


/**
 * FileName: DefaultSqlSession
 * Author:   xuan zongjun
 * Date:     2020/11/6 12:01
 * Description:
 */


public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    //处理器对象
    private Executor simpleExecutor = new SimpleExecutor();

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        //处理器对象

    }

    @Override
    public <E> List<E> selectList(String statementId, Object... param) throws Exception {
        MapperStatement mapperStatement = configuration.getMappedStatementMap().get( statementId );
        List<E> query = simpleExecutor.query( configuration, mapperStatement, param );
        return query;
    }

    //selectOne 中调用 selectList
    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<Object> objects = this.selectList( statementId, params );
        if (objects.size() == 1) {
            return (T) objects.get( 0 );
        } else {
            throw new RuntimeException( "返回结果过多" );
        }
    }

    @Override
    public void close() throws SQLException {
        simpleExecutor.close();
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {

        T o = (T) Proxy.newProxyInstance( mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // selectOne
                String methodName = method.getName();
                // className:namespace
                String className = method.getDeclaringClass().getName();
                //statementId
                String key = className + "." + methodName;
                MapperStatement mappedStatement = configuration.getMappedStatementMap().get( key );

                Type genericReturnType = method.getGenericReturnType();

                //判断是否实现泛型类型参数化
                if (genericReturnType instanceof ParameterizedType) {
                    return selectList( key, args );

                }
                return selectOne( key, args );

            }
        } );
        return o;
    }
}
